package cn.edu.neu.lab603.cloudeval.strategy.policy

import cn.edu.neu.lab603.cloudeval.entity.{PhysicalMachine => Host}
import cn.edu.neu.lab603.cloudeval.monitor.HostUtilizationMonitor
import cn.edu.neu.lab603.math.getLoessParameterEstimates

/** 使用 local regression 实现主机选择的策略。
  *
  * Created by yfwz100 on 2016/11/9.
  */
class HostSelectionPolicyLR(val utilMonitor: HostUtilizationMonitor,
                            val fallback: HostSelectionPolicyUtilizationBase,
                            val safety: Double = 1.0,
                            val capacityFactor: Double = 1.0)
  extends HostSelectionPolicyUtilizationBase(capacityFactor) with HistoryRecorder {

  import MigrationDef._

  override def isOverloadHost(host: Host): Boolean = {
    if (host.isIdle) return false

    val utilizationHistory = host.getUtilizationHistory
    val length: Int = 10 // we use 10 to make the regression responsive enough to latest values
    if (utilizationHistory.length < length) return fallback.isOverloadHost(host)
    val estimates: Array[Double] = try {
      getLoessParameterEstimates(utilizationHistory)
    } catch {
      case _: IllegalArgumentException => return fallback.isOverloadHost(host)
    }
    val migrationIntervals: Double = Math.ceil(getMaximumVmMigrationTime(host) / host.context.getSimulationInterval)
    var predictedUtilization: Double = estimates(0) + estimates(1) * (length + migrationIntervals)
    predictedUtilization *= safety

    addHistoryEntry(host, predictedUtilization)

    predictedUtilization >= 1
  }

  /** 获得 VM 迁移时间的估计参数
    *
    * @param host the host
    * @return the maximum vm migration time
    */
  protected def getMaximumVmMigrationTime(host: Host): Double = {
    host.getVMList.map(_.getUsedResMap("ram")).max / (host.capacity("bw").toDouble * 0.1)
  }

  override def toString = "LR"

  /** 估计利用率参数。
    *
    * @param utilizationHistoryReversed 利用率历史记录
    * @return 参数估计
    */
  protected def getParameterEstimates(utilizationHistoryReversed: Array[Double]): Array[Double] =
  getLoessParameterEstimates(utilizationHistoryReversed)
}
